package com.liruo.learn.spring.mvc.controller.valid.custom;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.reflect.MethodSignature;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.Validator;
import javax.validation.executable.ExecutableValidator;
import javax.validation.groups.ConvertGroup;
import javax.validation.groups.Default;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @Author:liruo
 * @Date:2023-06-08-00:10:37
 * @Desc
 */
//@Aspect
//@Component
@Slf4j
public class ValidAspect {
//    @Resource
    private Validator validator;


//    @Before("@annotation(javax.validation.Valid)")
    public void valid(JoinPoint joinPoint) throws Throwable {
        if (!JoinPoint.METHOD_EXECUTION.equals(joinPoint.getKind())) {
            return;
        }
        Signature signature = joinPoint.getSignature();
        log.info(signature.getName());


        ExecutableValidator executableValidator = validator.forExecutables();
        Method method = ((MethodSignature) signature).getMethod();

        Class<?>[] groups = getGroups(method);


        Set<ConstraintViolation<Object>> result = executableValidator.validateParameters(joinPoint.getThis(), method, joinPoint.getArgs(), groups);
        if (!result.isEmpty()) {
            throw new ConstraintViolationException(result);
        }

    }

    private static Class<?>[] getGroups(Method method) {
        Class<?>[] groups = new Class[0];
        ConvertGroup convertGroup = method.getAnnotation(ConvertGroup.class);
        if(convertGroup != null){
            groups = new Class[]{Default.class, convertGroup.to()};
        }
        ConvertGroup.List convertGroups = method.getAnnotation(ConvertGroup.List.class);
        if(convertGroups != null){
            List<Class<?>> groupList = Arrays.stream(convertGroups.value()).map(ConvertGroup::to).collect(Collectors.toList());
            groupList.add(Default.class);
            groups = groupList.toArray(Class[]::new);
        }

        return groups;
    }
}
